/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.merak.core;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;

import org.merak.core.web.HttpErrorException;
import org.merak.core.web.HttpException;

public final class Web {

	//~ Constructors ///////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
	protected Web() { }

	//~ Methods ////////////////////////////////////////////////////////////////////////////////////
	//**********************************************************************************************
	private HttpURLConnection createConnection(String url,CharSequence query) {
		
		try {
			// Open a connection to remote resource
			URL               addr = new URL(url);
			HttpURLConnection conn = (HttpURLConnection)addr.openConnection();

			/* Configure this connection as a form. It will do a post to the
			 * remote server requesting the data */
			conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			conn.setConnectTimeout(10000);
			conn.setDoOutput(true);

			// Set the request content
			if (query!=null) {
				Writer writer = new OutputStreamWriter(conn.getOutputStream());
				writer.write(query.toString());
				writer.close();
			}
			return conn;
		} 
		catch (IOException ex) {
			throw new HttpException("Cannot create http connection",ex);
		}

	}
	//**********************************************************************************************
	private HttpURLConnection createConnection(String url,byte[] content,String contentName) {
		
		try {
			// Open a connection to remote resource
			URL               addr = new URL(url);
			HttpURLConnection conn = (HttpURLConnection)addr.openConnection();

			// Set the content name
			if (contentName!=null) conn.setRequestProperty(
				"content-disposition", "attachment; filename=" + contentName
			);

			/* Configure this connection as octet-stream. */
			conn.setRequestProperty("Content-Type", "application/octet-stream");
			conn.setConnectTimeout(10000);
			conn.setDoOutput(true);

			// Set the request content
			if (content!=null) {
				conn.getOutputStream().write(content);
			}
			return conn;
		} 
		catch (IOException ex) {
			throw new HttpException("Cannot create http connection",ex);
		}

	}
	//**********************************************************************************************
	public String post(String url,CharSequence query) {
		
		// Auxiliary
		HttpURLConnection conn = this.createConnection(url,query);
		
		// Try retrieve the expected content
		try {
			return Application.io.readString(
					conn.getInputStream(), 
					conn.getContentEncoding(), 
					conn.getContentLength()
			);
		}
		// Try retrieve the expected error
		catch (IOException ex) {
			throw new HttpErrorException(conn);
		}
		// Disconnect from the remote host
		finally {
			conn.disconnect();
		}		
		
	}
	//**********************************************************************************************
	public String post(String url,byte[] content,String contentName) {
		
		// Auxiliary
		HttpURLConnection conn = this.createConnection(url,content,contentName);

		// Try retrieve the expected content
		try {
			return Application.io.readString(
					conn.getInputStream(), 
					conn.getContentEncoding(), 
					conn.getContentLength()
			);
		}
		// Try retrieve the expected error
		catch (IOException ex) {
			throw new HttpErrorException(conn);
		}
		// Disconnect from the remote host
		finally {
			conn.disconnect();
		}
		
	}	
	//**********************************************************************************************
	public File post(String url,CharSequence query,File output) {
		
		// Auxiliary
		HttpURLConnection conn = this.createConnection(url,query);
		
		// If no file is specified, create a temporary file	
		if (output==null) try {
			output = Application.io.createTempFile("download");			
		} 
		catch (IOException ex) {
			throw new HttpException("Cannot create temporary file",ex);
		}
		
		// Try retrieve the expected content
		try {
			Application.io.readBytes(
					conn.getInputStream(),
					new FileOutputStream(output)
			);
			return output;
		}
		// Try retrieve the expected error
		catch (IOException ex) {
			throw new HttpErrorException(conn);
		}
		// Disconnect from the remote host
		finally {
			conn.disconnect();
		}		
		
	}
	//**********************************************************************************************
	public File post(String url,byte[] content,String contentName,File output) {
		
		// Auxiliary
		HttpURLConnection conn = this.createConnection(url,content,contentName);
		
		// If no file is specified, create a temporary file	
		if (output==null) try {
			output = Application.io.createTempFile("download");			
		} 
		catch (IOException ex) {
			throw new HttpException("Cannot create temporary file",ex);
		}		
		
		// Try retrieve the expected content
		try {
			Application.io.readBytes(
					conn.getInputStream(),
					new FileOutputStream(output)
			);
			return output;
		}
		// Try retrieve the expected error
		catch (IOException ex) {
			throw new HttpErrorException(conn);
		}
		// Disconnect from the remote host
		finally {
			conn.disconnect();
		}		
		
	}
	//**********************************************************************************************
	public OutputStream post(String url,CharSequence query,OutputStream output) {

		// Auxiliary
		HttpURLConnection conn = this.createConnection(url,query);
		
		// Try retrieve the expected content
		try {
			Application.io.readBytes( conn.getInputStream(),output );
			return output;
		}
		// Try retrieve the expected error
		catch (IOException ex) {
			throw new HttpErrorException(conn);
		}
		// Disconnect from the remote host
		finally {
			conn.disconnect();
		}		

	}
	//**********************************************************************************************
	public OutputStream post(String url,byte[] content,String contentName,OutputStream output) {

		// Auxiliary
		HttpURLConnection conn = this.createConnection(url,content,contentName);
		
		// Try retrieve the expected content
		try {
			Application.io.readBytes( conn.getInputStream(),output );
			return output;
		}
		// Try retrieve the expected error
		catch (IOException ex) {
			throw new HttpErrorException(conn);
		}
		// Disconnect from the remote host
		finally {
			conn.disconnect();
		}		

	}
	//**********************************************************************************************
	public byte[] postForBytes(String url,CharSequence query) {
		
		// Auxiliary
		HttpURLConnection conn = this.createConnection(url,query);
		
		// Try retrieve the expected content
		try {
			return Application.io.readBytes(
					conn.getInputStream(), 
					conn.getContentLength()
			);
		}
		// Try retrieve the expected error
		catch (IOException ex) {
			throw new HttpErrorException(conn);
		}
		// Disconnect from the remote host
		finally {
			conn.disconnect();
		}		
		
	}
	//**********************************************************************************************
	public byte[] postForBytes(String url,byte[] content,String contentName) {
		
		// Auxiliary
		HttpURLConnection conn = this.createConnection(url,content,contentName);
		
		// Try retrieve the expected content
		try {
			return Application.io.readBytes(
					conn.getInputStream(), 
					conn.getContentLength()
			);
		}
		// Try retrieve the expected error
		catch (IOException ex) {
			throw new HttpErrorException(conn);
		}
		// Disconnect from the remote host
		finally {
			conn.disconnect();
		}		
		
	}	
	//**********************************************************************************************

}
